package edu.ilstu.mind.ise.ccp.impl.queued;

import java.util.Collections;
import java.util.Map;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

import edu.ilstu.mind.ise.ccp.message.Message;
import edu.ilstu.mind.ise.ccp.mindmodule.MindModule;

class QueuedMessageRouter extends Thread {
	private final BlockingQueue<Message> messageQueue = new LinkedBlockingQueue<Message>();
	private final MindModule mindModule;
	private final Map<String, QueuedModuleThread> moduleThreads;

	public QueuedMessageRouter(MindModule mindModule, Map<String, QueuedModuleThread> moduleThreads) {
		this.mindModule = mindModule;
		this.moduleThreads = Collections.synchronizedMap(moduleThreads);
	}

	public void enqueue(Message message) {
		// Synchronization is in BlockingQueue implementation
		try {
			messageQueue.put(message);
		} catch (InterruptedException e) {
			// translate to runtime exception. this shouldn't happen.
			throw new RuntimeException(e);
		}
	}

	@Override
	public void run() {
		try {
			while (true) {
				// take message from queue
				Message message = messageQueue.take();
				if (message != null) {
					// route message through mind module
					boolean process = mindModule.onMessage(message);
					// check if mind module approves of the message
					if (process) {
						// get the module thread that this message is for
						QueuedModuleThread moduleThread = moduleThreads.get(message.getTo());
						// if the module exists, enqueue the message for it
						if (moduleThread != null) {
							moduleThread.enqueue(message);
						}
					}
				}
			}
		} catch (InterruptedException e) {
			// exit the thread
		}
	}
}